﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TankController.Dominio;

namespace TankController
{
    public partial class UcConfigurarControladorMF : UserControl
    {
        private const int CONTROLADOR_MF = 0;
        private const int CONFIGURA_KI = 1;
        private const int CONFIGURA_KD = 2;

        private FormConfigurar formConfigurar;
        private ControladorMalhaFechada controlador;
        private TipoPosicaoControlador tipoPosicao;

        public ControladorMalhaFechada Controlador
        {
            get { return controlador; }
        }

        public UcConfigurarControladorMF()
        {
            InitializeComponent();

            MontarTiposControlador();
        }

        public UcConfigurarControladorMF(FormConfigurar formConfigurar, TipoPosicaoControlador tipoPosicao)
            : this()
        {
            this.formConfigurar = formConfigurar;
            this.tipoPosicao = tipoPosicao;
        }

        private void MontarTiposControlador()
        {
            ArrayList tiposControlador = new ArrayList();

            tiposControlador.Add(new { Valor = TipoControlador.P, Descricao = "Controlador P" });
            tiposControlador.Add(new { Valor = TipoControlador.PI, Descricao = "Controlador PI" });
            tiposControlador.Add(new { Valor = TipoControlador.PD, Descricao = "Controlador PD" });
            tiposControlador.Add(new { Valor = TipoControlador.PID, Descricao = "Controlador PID" });
            tiposControlador.Add(new { Valor = TipoControlador.PI_D, Descricao = "Controlador PI-D" });

            lbxTipoControlador.ValueMember = "Valor";
            lbxTipoControlador.DisplayMember = "Descricao";

            lbxTipoControlador.DataSource = tiposControlador;

            lbxTipoControlador.SelectedIndex = 0;
        }

        public void ValidarCampos()
        {
            int parseResultInt;
            double parseResultDouble;

            if (!int.TryParse(txtPeriodoControlador.Text, out parseResultInt))
            {
                throw new ApplicationException("Valor de período do controlador inválido.");
            }

            if (!double.TryParse(txtLimiteSeguranca.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de limite de segurança do controlador inválido.");
            }

            if (!double.TryParse(txtKp.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de Kp inválido.");
            }

            if ((TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                rbtKi.Checked && !double.TryParse(txtKi.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de Ki inválido.");
            }

            if ((TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                rbtTi.Checked && !double.TryParse(txtTi.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de Ti inválido.");
            }

            if ((TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                rbtKd.Checked && !double.TryParse(txtKd.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de Kd inválido.");
            }

            if ((TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                rbtTd.Checked && !double.TryParse(txtTd.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de Td inválido.");
            }
        }

        public void MontarControlador()
        {
            int periodo = int.Parse(txtPeriodoControlador.Text);
            double limiteSeguranca = double.Parse(txtLimiteSeguranca.Text.Replace('.', ',')) / 100;

            controlador = GetConfiguracao()[CONTROLADOR_MF] as ControladorMalhaFechada;

            double kp = 0;
            double ki = 0;
            double kd = 0;

            kp = double.Parse(txtKp.Text.Replace('.', ','));

            if (TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue)
            {
                ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
            }

            if (TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue)
            {
                kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));
            }

            switch ((TipoControlador)lbxTipoControlador.SelectedValue)
            {
                case TipoControlador.P:
                    if (controlador is ControladorP)
                    {
                        (controlador as ControladorP).SetGanho(kp);
                    }
                    else
                    {
                        controlador = new ControladorP(tipoPosicao, kp);
                    }
                    break;
                case TipoControlador.PI:
                    if (controlador is ControladorPI)
                    {
                        (controlador as ControladorPI).SetGanho(kp, ki);
                    }
                    else
                    {
                        controlador = new ControladorPI(tipoPosicao, kp, ki, periodo);
                    }
                    break;
                case TipoControlador.PD:
                    if (controlador is ControladorPD)
                    {
                        (controlador as ControladorPD).SetGanho(kp, kd);
                    }
                    else
                    {
                        controlador = new ControladorPD(tipoPosicao, kp, kd, periodo);
                    }
                    break;
                case TipoControlador.PID:
                    if (controlador is ControladorPID)
                    {
                        (controlador as ControladorPID).SetGanho(kp, ki, kd);
                    }
                    else
                    {
                        controlador = new ControladorPID(tipoPosicao, kp, ki, kd, periodo);
                    }
                    break;
                case TipoControlador.PI_D:
                    if (controlador is ControladorPI_D)
                    {
                        (controlador as ControladorPI_D).SetGanho(kp, ki, kd);
                    }
                    else
                    {
                        controlador = new ControladorPI_D(tipoPosicao, kp, ki, kd, periodo);
                    }
                    break;
                default:
                    throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
            }

            controlador.Periodo = periodo;
            controlador.LimiteSeguranca = limiteSeguranca;
        }

        public void AtualizarCampos()
        {
            Object[] configuracao = GetConfiguracao();
            controlador = configuracao[CONTROLADOR_MF] as ControladorMalhaFechada;
            Boolean configuraKi = (Boolean)configuracao[CONFIGURA_KI];
            Boolean configuraKd = (Boolean)configuracao[CONFIGURA_KD];

            if (controlador is ControladorP)
            {
                txtKp.Text = (controlador as ControladorP).Kp.ToString();
            }
            else if (controlador is ControladorPI)
            {
                txtKp.Text = (controlador as ControladorPI).Kp.ToString();

                if (Global.ConfiguraKi1)
                {
                    rbtKi.Checked = true;
                    txtTi.Text = "";
                    txtKi.Text = (controlador as ControladorPI).Ki.ToString();
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controlador as ControladorPI).Ki).ToString();
                }
            }
            else if (controlador is ControladorPD)
            {
                txtKp.Text = (controlador as ControladorPD).Kp.ToString();

                if (Global.ConfiguraKd1)
                {
                    rbtKd.Checked = true;
                    txtTd.Text = "";
                    txtKd.Text = (controlador as ControladorPD).Kd.ToString();
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controlador as ControladorPD).Kd).ToString();
                }
            }
            else if (controlador is ControladorPID)
            {
                txtKp.Text = (controlador as ControladorPID).Kp.ToString();

                if (Global.ConfiguraKi1)
                {
                    rbtKi.Checked = true;
                    txtTi.Text = "";
                    txtKi.Text = (controlador as ControladorPID).Ki.ToString();
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controlador as ControladorPID).Ki).ToString();
                }

                if (Global.ConfiguraKd1)
                {
                    rbtKd.Checked = true;
                    txtTd.Text = "";
                    txtKd.Text = (controlador as ControladorPID).Kd.ToString();
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controlador as ControladorPID).Kd).ToString();
                }
            }
            else if (controlador is ControladorPI_D)
            {
                txtKp.Text = (controlador as ControladorPI_D).Kp.ToString();

                if (Global.ConfiguraKi1)
                {
                    rbtKi.Checked = true;
                    txtTi.Text = "";
                    txtKi.Text = (controlador as ControladorPI_D).Ki.ToString();
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controlador as ControladorPI_D).Ki).ToString();
                }

                if (Global.ConfiguraKd1)
                {
                    rbtKd.Checked = true;
                    txtTd.Text = "";
                    txtKd.Text = (controlador as ControladorPI_D).Kd.ToString();
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controlador as ControladorPI_D).Kd).ToString();
                }
            }
            else
            {
                throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
            }
        }

        private void lbxTipoControlador_SelectedIndexChanged(object sender, EventArgs e)
        {
            TipoControlador controlador = (TipoControlador)lbxTipoControlador.SelectedValue;

            switch (controlador)
            {
                case TipoControlador.P:
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = false;
                    pnlAcaoDerivativa.Enabled = false;
                    break;
                case TipoControlador.PI:
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = true;
                    pnlAcaoDerivativa.Enabled = false;
                    break;
                case TipoControlador.PD:
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = false;
                    pnlAcaoDerivativa.Enabled = true;
                    break;
                case TipoControlador.PID:
                case TipoControlador.PI_D:
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = true;
                    pnlAcaoDerivativa.Enabled = true;
                    break;
                default:
                    throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
            }
        }

        private void rbtAcaoIntegrativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKi.Checked)
            {
                txtKi.Enabled = true;
                txtTi.Enabled = false;

                rbtKd.Checked = true;

                SetConfiguracaoKi(true);
            }
            else
            {
                txtKi.Enabled = false;
                txtTi.Enabled = true;

                rbtTd.Checked = true;

                SetConfiguracaoKi(false);
            }
        }

        private void rbtAcaoDerivativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKd.Checked)
            {
                txtKd.Enabled = true;
                txtTd.Enabled = false;

                rbtKi.Checked = true;

                SetConfiguracaoKd(true);
            }
            else
            {
                txtKd.Enabled = false;
                txtTd.Enabled = true;

                rbtTi.Checked = true;

                SetConfiguracaoKd(false);
            }
        }

        private Object[] GetConfiguracao()
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    return new Object[] { Global.Controlador1, Global.ConfiguraKi1, Global.ConfiguraKd1 };
                case TipoPosicaoControlador.Controlador2:
                    return new Object[] { Global.Controlador2, Global.ConfiguraKi2, Global.ConfiguraKd2 };
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        private void SetConfiguracaoKi(Boolean configuraKi)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    Global.ConfiguraKi1 = configuraKi;

                    break;
                case TipoPosicaoControlador.Controlador2:
                    Global.ConfiguraKi2 = configuraKi;

                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        private void SetConfiguracaoKd(Boolean configuraKd)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    Global.ConfiguraKd1 = configuraKd;

                    break;
                case TipoPosicaoControlador.Controlador2:
                    Global.ConfiguraKd2 = configuraKd;

                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }
    }
}
